home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Games / Chess / Source / Chess.m < prev    next >
Text File  |  1994-04-01  |  20KB  |  862 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <sys/param.h>
  4. #include <sys/times.h>
  5. #include <sys/file.h>
  6. #include <pwd.h>
  7.  
  8.  
  9. #import <appkit/appkit.h>
  10.  
  11. #import "chess_strings.h"
  12. #import "Chess.h"
  13. #import "gnuchess.h"
  14. #import "gnuglue.h"
  15. #import "Clock.h"
  16. #import "Board.h"
  17. #import "Board3D.h"
  18. #import "ResponseMeter.h"
  19.  
  20. extern id NXWait, NXArrow;
  21. extern short PieceList[2][16];
  22. extern short PieceCnt[2];
  23. extern gnuchess_main_init();
  24. extern NewGame();
  25. extern algbr();
  26. /* extern getsectdata(); */
  27. extern VerifyMove();
  28. extern SelectMoveStart();
  29. extern SelectMoveEnd();
  30. extern SelectLoop();
  31.  
  32. short GameQueens[240];
  33.  
  34.  
  35. #ifdef NeXT_DEBUG
  36. #define chess_debug(x) { printf x; }
  37. #else
  38. #define chess_debug(x)
  39. #endif
  40.  
  41. @implementation Chess
  42.  
  43. + initialize
  44. {
  45.   gnuchess_main_init();
  46.   return self;
  47. }
  48.  
  49. + new
  50. {
  51.   self = [super new];
  52.   pwen = getpwuid( getuid() );
  53.  
  54.   pref.time_control_minutes = 5;
  55.   pref.time_control_moves = 60;
  56.   pref.opponent = white;
  57.   pref.computer = black;
  58.   pref.bothsides = false;
  59.   pref.cheat = YES;
  60.   pref.white_name = pwen->pw_gecos;
  61.   pref.black_name = (char *)COMPUTER;
  62.   white_color = NX_COLORWHITE;
  63.   black_color = NX_COLORWHITE;
  64.   [self newGame: self];
  65.   return self;
  66. }
  67.   
  68. /*
  69.   Get InterfaceBuilder outlets.
  70. */
  71. - clockWindow { return clockWindow; return self; }
  72. - whiteClock { return whiteClock; }
  73. - blackClock { return blackClock; }
  74. - whiteMeter { return whiteMeter; }
  75. - blackMeter { return blackMeter; }
  76. - setBoard3D: anObject { gameBoard = board3D = anObject; return self;  }
  77. - setBoard2D: anObject { board2D = anObject; [board2D removeFromSuperview]; return self;  }
  78. /*
  79.   Action methods for InterfaceBuilder objects.
  80. */
  81.  
  82. - print: sender
  83. {
  84.   [gameBoard printPSCode: sender];
  85.   return self;
  86. }
  87.  
  88. - (int) openFile:(char const *)s ok:(int *)flag {
  89.     GetGame( s );
  90.     *flag = YES;
  91.     return 0;
  92. }
  93. - setBlackColor:sender
  94. {
  95.     float sat;
  96.     
  97.     black_color = [sender color];
  98.     black_color = NXChangeAlphaComponent(black_color,1.0);
  99.     black_color = NXChangeBrightnessComponent(black_color,1.0);
  100.     sat = NXSaturationComponent(black_color);
  101.     if(sat > .21 ) black_color = NXChangeSaturationComponent(black_color,.21);
  102.     [self renderPreview];
  103.     
  104.     return self;
  105. }
  106. - setWhiteColor:sender
  107. {
  108.     float sat;
  109.     
  110.     white_color = [sender color];
  111.     white_color = NXChangeAlphaComponent(white_color,1.0);
  112.     white_color = NXChangeBrightnessComponent(white_color,1.0);
  113.     sat = NXSaturationComponent(white_color);
  114.     if(sat > .21 ) white_color = NXChangeSaturationComponent(white_color,.21);
  115.     [self renderPreview];
  116.     
  117.     return self;
  118. }
  119.  
  120.  
  121. - renderPreview
  122. {
  123.     NXRect r;
  124.     NXPoint pt = {0.0,0.0};
  125.     static id blacky = nil;
  126.     static id whitey = nil;
  127.     static id image1 = nil;
  128.     static id image2 = nil;
  129.     
  130.     
  131.     if(!whitey) whitey = [NXImage newFromSection: "3d_white_sample.tiff"];
  132.     if(!blacky) blacky = [NXImage newFromSection: "3d_black_sample.tiff"];
  133.     if(!image1) image1 = [NXImage newFromSection: "3d_black_sample.tiff"];
  134.     if(!image2) image2 = [NXImage newFromSection: "3d_black_sample.tiff"];
  135.     
  136.     [whitey getSize:&r.size];
  137.     r.origin.x = r.origin.y = 0.0;
  138.     
  139.     [image2 lockFocus];
  140.     [whitey composite:NX_COPY fromRect:&r toPoint:&pt];
  141.     [image2 unlockFocus];
  142.     [image1 lockFocus];
  143.     [whitey composite:NX_COPY fromRect:&r toPoint:&pt];
  144.     [image1 unlockFocus];
  145.     
  146.     [image1 lockFocus];
  147.     NXSetColor(white_color);
  148.     PScompositerect(0.0,0.0,r.size.width,r.size.height, NX_PLUSD);
  149.     [image1 unlockFocus];
  150.     
  151.     [image2 lockFocus];
  152.     [image1 composite:NX_SATOP fromRect:&r toPoint:&pt];
  153.     [image2 unlockFocus];
  154.     
  155.     [[whitesample image] lockFocus];
  156.     [image2 composite:NX_COPY fromRect:&r toPoint:&pt];
  157.     [[whitesample image] unlockFocus];
  158.     
  159.     
  160.     [image2 lockFocus];
  161.     [blacky composite:NX_COPY fromRect:&r toPoint:&pt];
  162.     [image2 unlockFocus];
  163.     [image1 lockFocus];
  164.     [blacky composite:NX_COPY fromRect:&r toPoint:&pt];
  165.     [image1 unlockFocus];
  166.     
  167.     [image1 lockFocus];
  168.     NXSetColor(black_color);
  169.     PScompositerect(0.0,0.0,r.size.width,r.size.height, NX_PLUSD);
  170.     [image1 unlockFocus];
  171.     
  172.     [image2 lockFocus];
  173.     [image1 composite:NX_SATOP fromRect:&r toPoint:&pt];
  174.     [image2 unlockFocus];
  175.     
  176.     [[blacksample image] lockFocus];
  177.     [image2 composite:NX_COPY fromRect:&r toPoint:&pt];
  178.     [[blacksample image] unlockFocus];
  179.  
  180.     [blacksample display];
  181.     [whitesample display];
  182.     return self;
  183.  
  184. }
  185. - renderColors:sender
  186. {
  187.     id image2;
  188.     id image1;
  189.     NXRect r;
  190.     NXPoint pt = {0.0,0.0};
  191.     
  192.     
  193.     if( gameBoard != board3D ) return self;
  194.     image1 = [NXImage newFromSection: "3d_pieces.tiff"];
  195.     image2 = [gameBoard backgroundBitmap];
  196.     
  197.     [image2 getSize:&r.size];
  198.     r.origin.x = r.origin.y = 0.0;
  199.     [image2 lockFocus];
  200.     [image1 composite:NX_COPY fromRect:&r toPoint:&pt];
  201.     [image2 unlockFocus];
  202.     
  203.     [image1 lockFocus];
  204.     NXSetColor(white_color);
  205.     PScompositerect(0.0,0.0,336.0,r.size.height, NX_PLUSD);
  206.     NXSetColor(black_color);
  207.     PScompositerect(336.0,0.0,336.0,r.size.height, NX_PLUSD);
  208.     [image1 unlockFocus];
  209.     
  210.     [image2 lockFocus];
  211.     [image1 composite:NX_SATOP fromRect:&r toPoint:&pt];
  212.     [image2 unlockFocus];
  213.     
  214.     [gameBoard display];
  215.     if (image1) [image1 free];
  216.     return self;
  217. }
  218. - plastic: sender
  219. {
  220.   id plastic;
  221.   
  222.   if( gameBoard == board2D )
  223.     return self;
  224.     
  225.   plastic = [NXImage newFromSection: "3d_board.tiff"];
  226.   [gameBoard setBackgroundBitmap: plastic];
  227.   [gameBoard display];
  228.   return self;
  229. }
  230.  
  231.  
  232. - gameBoard { return gameBoard; }
  233. - view2D: sender
  234. {
  235.   NXRect b;
  236.   id v;
  237.   
  238.   if( gameBoard == board2D )
  239.     return self;
  240.     
  241.   v = [gameBoard superview];
  242.   [v getBounds: &b];
  243.   [v lockFocus];
  244.   PSgsave();
  245.   PSsetgray( NX_BLACK );
  246.   PSrectfill( 0, 0, b.size.width, b.size.height );
  247.   PSgrestore();
  248.   [v unlockFocus];
  249.   
  250.   [gameBoard removeFromSuperview];
  251.   [v addSubview: board2D];
  252.   gameBoard = board2D;
  253.   [gameBoard layoutBoard: board color: color];
  254.   [gameBoard display];
  255.   NXPing();
  256.   return self;
  257. }
  258.  
  259. - view3D: sender
  260. {
  261.   id v;
  262.   
  263.   if( gameBoard == board3D )
  264.     return self;
  265.     
  266.   v = [gameBoard superview];
  267.   [gameBoard removeFromSuperview];
  268.   [v addSubview: board3D];
  269.   gameBoard = board3D;
  270.   [gameBoard layoutBoard: board color: color];
  271.   [gameBoard display];
  272.   NXPing();
  273.   return self;
  274. }
  275.  
  276. - levelSliding: sender
  277. /*
  278.   Change the text displayed below the level slider to indicate
  279.   what the level means.
  280. */
  281. {
  282.   char buf[32];
  283.   int moves = 0, minutes = 0;
  284.   
  285.   Level = [levelSlider intValue];
  286.   switch (Level){
  287.     case 1 : moves = 60; minutes = 5; break;
  288.     case 2 : moves = 60; minutes = 15; break;
  289.     case 3 : moves = 60; minutes = 30; break;
  290.     case 4 : moves = 40; minutes = 30; break;
  291.     case 5 : moves = 40; minutes = 60; break;
  292.     case 6 : moves = 40; minutes = 120; break;
  293.     case 7 : moves = 40; minutes = 240; break;
  294.     case 8 : moves = 1; minutes = 15; break;
  295.     case 9 : moves = 1; minutes = 60; break;
  296.     case 10 : moves = 1; minutes = 600; break;
  297.   }
  298.   if( moves > 1 )
  299.     sprintf( buf, "%d moves in %d minutes", moves, minutes );
  300.   else
  301.     sprintf( buf, "%d move in %d minutes", moves, minutes );
  302.   [levelText setStringValue: buf];
  303.   return self;
  304. }
  305.  
  306. - setPreferences: sender
  307. /*
  308.   Actually set the preferences.
  309. */
  310. {
  311.   int whiteSide = [whiteSideMatrix selectedRow];
  312.   int blackSide = [blackSideMatrix selectedRow];
  313.   int change = NO;
  314.   int button;
  315.   
  316.   
  317.   button = NXRunAlertPanel( 0,
  318.       "Start a new game with these Preferences?", "Yes", "No", 0
  319.   );
  320.   switch( (Level = [levelSlider intValue]) ){
  321.     case 1 : pref.time_control_moves = 60; pref.time_control_minutes = 5; break;
  322.     case 2 : pref.time_control_moves = 60; pref.time_control_minutes = 15; break;
  323.     case 3 : pref.time_control_moves = 60; pref.time_control_minutes = 30; break;
  324.     case 4 : pref.time_control_moves = 40; pref.time_control_minutes = 30; break;
  325.     case 5 : pref.time_control_moves = 40; pref.time_control_minutes = 60; break;
  326.     case 6 : pref.time_control_moves = 40; pref.time_control_minutes = 120; break;
  327.     case 7 : pref.time_control_moves = 40; pref.time_control_minutes = 240; break;
  328.     case 8 : pref.time_control_moves = 1; pref.time_control_minutes = 15; break;
  329.     case 9 : pref.time_control_moves = 1; pref.time_control_minutes = 60; break;
  330.     case 10 : pref.time_control_moves = 1; pref.time_control_minutes = 600; break;
  331.   }
  332.   
  333.   if( whiteSide == 0 && blackSide == 0 ){
  334.     pref.bothsides = 1;
  335.     pref.opponent = white;
  336.     pref.computer = black;
  337.   }
  338.   else if( whiteSide == 1 && blackSide == 0 ){
  339.     pref.bothsides = 0;
  340.     pref.opponent = white;
  341.     pref.computer = black;
  342.   }
  343.   else if( whiteSide == 0 && blackSide == 1 ){
  344.     pref.bothsides = 0;
  345.     pref.opponent = black;
  346.     pref.computer = white;
  347.   }
  348.   else
  349.     chess_debug(( "Unsupported combination\n" ));
  350.     
  351.   pref.white_name = (char *)[whiteName stringValue];
  352.   pref.black_name = (char *)[blackName stringValue];
  353.   if ( button == NX_ALERTDEFAULT ) {
  354.       [self newGame: self];
  355.   }
  356.   return self;
  357. }
  358.  
  359. - usePreferences
  360. /*
  361.   Use current preferences
  362. */
  363. {
  364.   TCmoves = pref.time_control_moves;
  365.   TCminutes = pref.time_control_minutes;
  366.   TCflag = (TCmoves > 1);
  367.   SetTimeControl();
  368.   
  369.   bothsides = pref.bothsides;
  370.   opponent = pref.opponent;
  371.   computer = pref.computer;
  372.   if( bothsides ){
  373.     [startButton setEnabled: YES];
  374.     [startButton display];
  375.   }
  376.   else{
  377.     [startButton setEnabled: NO];
  378.     [startButton display];
  379.   }
  380.     
  381.   [self setWhiteName: pref.white_name blackName: pref.black_name];
  382.   return self;
  383. }
  384.  
  385. - openGame: sender
  386. /*
  387.   Read a saved game.
  388. */
  389. {
  390.   id op = [OpenPanel new];
  391.   const char *types[2];
  392.   
  393.   types[0] = "chess";
  394.   types[1] = 0;
  395.   finished = 0;
  396.   [op setRequiredFileType: "chess"];
  397.   if( [op runModalForTypes: types] ){
  398.     if( filename )
  399.       free( filename );
  400.     filename = (char *)malloc( strlen( [op filename] ) + 1 );
  401.     strcpy( filename, [op filename] );
  402.     GetGame( filename );
  403.   }
  404.   return self;
  405. }
  406.   
  407. - saveAsGame: sender
  408. /*
  409.   Save a game.
  410. */
  411. {
  412.   id sp = [SavePanel new];
  413.   
  414.   [sp setRequiredFileType: "chess"];
  415.   if( [sp runModal] ){
  416.     if( filename )
  417.       free( filename );
  418.     filename = (char *)malloc( strlen( [sp filename] ) + 1 );
  419.     strcpy( filename, [sp filename] );
  420.     SaveGame( filename );
  421.   }
  422.   return self;
  423. }
  424.  
  425. - saveGame: sender
  426. {
  427.   if( filename )  
  428.     SaveGame( filename );
  429.   else
  430.     [self saveAsGame: sender];
  431.   return self;
  432. }
  433.   
  434. - listGame: sender
  435. /*
  436.   Save a game.
  437. */
  438. {
  439.   id sp = [SavePanel new];
  440.   [sp setRequiredFileType: 0];
  441.   if( [sp runModal] )
  442.     ListGame( [sp filename] );
  443.   return self;
  444. }
  445.  
  446. - newGame: sender
  447. /*
  448.   Start a new game.
  449. */
  450. {
  451.   forceCount = hintCount = undoCount = 0;
  452.   finished = 0;
  453.   NewGame();
  454.   [self setTitle];
  455.   [self usePreferences];
  456.   if( bothsides ){
  457.     [startButton setEnabled: YES];
  458.     [startButton display];
  459.   }
  460.   else{
  461.     [startButton setEnabled: NO];
  462.     [startButton display];
  463.      if( computer == white && !mate && !quit )
  464.       [self selectMove: computer iop: 1];
  465.   }
  466.   return self;
  467. }
  468.  
  469. - chooseSide: sender
  470. /*
  471.   Set the text fields next to the side matrices.
  472. */
  473. {
  474.   int whiteSide = [whiteSideMatrix selectedRow];
  475.   int blackSide = [blackSideMatrix selectedRow];
  476.   
  477.   if( whiteSide == 1 && blackSide == 0 ){
  478.     [whiteName setStringValue: pwen->pw_gecos];
  479.     [blackName setStringValue: "Computer"];
  480.   }
  481.   else if( whiteSide == 0 && blackSide == 1 ){
  482.     [blackName setStringValue: pwen->pw_gecos];
  483.     [whiteName setStringValue: "Computer"];
  484.   }
  485.   else if( whiteSide == 1 && blackSide == 1 ){
  486.     [blackName setStringValue: pwen->pw_gecos];
  487.     [whiteName setStringValue: pwen->pw_gecos];
  488.   }
  489.   else{
  490.     [blackName setStringValue: "Computer"];
  491.     [whiteName setStringValue: "Computer"];
  492.   }
  493.   return self;
  494. }
  495.  
  496.  
  497. -forceMove: sender
  498. {
  499.   timeout = true;
  500.   return self;
  501. }
  502.  
  503. BOOL playing = NO;
  504.  
  505.     
  506. - startGame: sender
  507. {
  508.   id menuList = [[self mainMenu] itemList];
  509.   int i, r, c;
  510.   
  511.   [menuList getNumRows: &r numCols: &c];
  512.   if( [sender state] == 1 && playing == NO ){
  513.     quit = false;
  514.     playing = YES;
  515.     
  516.     /* This is the loop that makes the computer play.  It can be terminated */
  517.     /* by several conditions.  The "Stop" button may be clicked, cmd-. may  */
  518.     /* be pressed, or the game may end. */
  519.     while( !mate && !quit && !finished && playing )
  520.       [self selectMove: player iop: 1];
  521.     quit = true;
  522.     timeout = true;
  523.     playing = NO;
  524.     for( i = 0; i < r; i++ )
  525.       [[menuList cellAt: i :0] setEnabled: YES];
  526.     [[self mainMenu] display];
  527.     [sender setState: 0];
  528.   }
  529.   else if( [sender state] == 0 && playing == YES ){
  530.     quit = true;
  531.     timeout = true;
  532.     playing = NO;
  533.     for( i = 0; i < r; i++ )
  534.       [[menuList cellAt: i :0] setEnabled: YES];
  535.     [[self mainMenu] display];
  536.   }
  537.   return self;
  538. }
  539.  
  540. - hint: sender
  541. /*
  542.   Give the player a hint.
  543. */
  544. {
  545.   short from = hint>>8;
  546.   short to = hint & 0xff;
  547.   int row, col;
  548.   
  549.   if( hint ){
  550.     algbr( (short)(hint>>8), (short)(hint & 0xff), false );
  551.     chess_debug(( "hint:  %s\n", mvstr1 ));
  552.     hintCount++;
  553.     row = (int)(from / 8);
  554.     col = (int)(from % 8);
  555.     [gameBoard highlightSquareAt: row : col];
  556.     row = (int)(to / 8);
  557.     col = (int)(to % 8);
  558.     [gameBoard highlightSquareAt: row : col];
  559.     [self setTitle];
  560.   }
  561.   else
  562.     NXRunAlertPanel( 0, "I don't have a hint.", 0, 0, 0 );
  563.   return self;
  564. }
  565.  
  566. - undoMove: sender
  567. /*
  568.   Undo last two half moves.
  569. */
  570. {
  571.   if( GameCnt >= 0 ){
  572.     Undo(); Undo();
  573.     undoCount++;
  574.     // mate = false;    /* Glenn Reid (NeXT) Mon Apr 16 00:39:35 PDT 1990 */
  575.     [self setTitle];
  576.   }
  577.   else
  578.     NXRunAlertPanel( 0, "No more moves to undo.", 0, 0, 0 );
  579.   return self;
  580. }
  581.  
  582. - info: sender
  583. {
  584.   char *copyright;
  585.   int copy_size;
  586.   NXStream *copy_stream;
  587.   id text;
  588.   
  589.   copyright = (char *)getsectdata( "__COPYRIGHT", "COPYING", ©_size);
  590.   if( copyright != NULL ){
  591.     copy_stream = NXOpenMemory( copyright, copy_size, NX_READONLY );
  592.     text = [infoScroll docView];
  593.     [text readText: copy_stream];
  594.     [text sizeToFit];
  595.     [text setFont: [Font newFont: "Times" size: 14.0]];
  596.     [infoScroll display];
  597.   }
  598.   [infoPanel makeKeyAndOrderFront: sender];
  599.   return self;
  600. }
  601.  
  602.  
  603.  
  604. /*
  605.   Support methods.
  606. */
  607.  
  608. - setFinished: (int) f { finished = f; [self finishedAlert]; return self; }
  609. - (int)finished { return finished; }
  610. - (int)bothsides { return pref.bothsides; }
  611. - storePosition: (int) row : (int) col {
  612.     currentRow = row;
  613.     currentCol = col;
  614.   return self;
  615. }
  616. - showPosition: sender
  617. {
  618.     [gameBoard highlightSquareAt: currentRow : currentCol];
  619.     [gameBoard flashSquareAt: currentRow : currentCol];
  620.     return self;
  621. }
  622.  
  623. - finishedAlert
  624. {
  625.   printf( "opponent %d, computer %d\n", opponent, computer );
  626.   switch( finished ){
  627.   case DRAW_GAME:
  628.     NXRunAlertPanel( 0, "The game is a draw.", 0, 0, 0 );
  629.     break;
  630.   case WHITE_MATE:
  631.     NXRunAlertPanel( 0, "The game is over.  Black wins.", 0, 0, 0 );
  632.     break;
  633.   case BLACK_MATE:
  634.     NXRunAlertPanel( 0, "The game is over.  White wins.", 0, 0, 0 );
  635.     break;
  636.   case OPPONENT_MATE:
  637.     NXRunAlertPanel( 0, "The game is over.\nCongratulations, you win.", 0, 0, 0 );
  638.     break;
  639.   default:
  640.     break;
  641.   }
  642.   return self;
  643. }
  644.  
  645. - (int)makeMoveFrom: (int)r1 : (int)c1 to: (int)r2 : (int)c2
  646.   unsigned short mv;
  647.   char *move;
  648.   short oldguy, newguy;
  649.   
  650.   oldguy = [gameBoard typeAt: r1 : c1];
  651.   move = convert_rc( r1, c1, r2, c2, [gameBoard typeAt: r1 : c1] );
  652.   player = opponent;
  653.   if( !VerifyMove( move, 0, &mv ) ){
  654.     ShowMessage( "Illegal move" );
  655.     NXBeep();
  656.     return( 0 );
  657.   }
  658.   else {
  659.     /* if your pawn is promoted to queen and then you Undo, the queen
  660.        should turn back into a pawn.
  661.        Glenn Reid (NeXT) Mon Apr 16 00:49:26 PDT 1990
  662.     */
  663.     newguy = [gameBoard typeAt: r2 : c2];
  664.     if ( (newguy == queen) && (oldguy == pawn) ) {
  665.     fprintf ( stderr, "pawn becomes queen...\n" );
  666.     GameQueens[GameCnt] = oldguy;
  667.     } else {
  668.     GameQueens[GameCnt] = 0;
  669.     }
  670.     chess_debug(( "opponent move time %d move %s\n",
  671.        GameList[GameCnt].time, move ));
  672.     [self updateClocks: opponent];
  673.     InCheck();
  674.     NXPing();
  675.     [gameBoard layoutBoard: board color: color];
  676.     [gameBoard display];
  677.     NXPing();
  678.     Sdepth = 0;
  679.     ft = 0;
  680.     if( !(quit || mate || force) )
  681.       [self selectMove: computer iop: 1];
  682.   }
  683.  return( 1 );
  684. }
  685.  
  686. - selectMove: (int)side iop: (int)iop
  687. {
  688.   id menuList = [[self mainMenu] itemList];
  689.   int i, r, c;
  690.   
  691.   if( side == black ) {
  692.     ShowMessage( "Black's move" );
  693.   } else {
  694.     ShowMessage( "White's move" );
  695.   }
  696.     
  697.   [forceButton setEnabled: YES];
  698.   [forceButton display];
  699.   NXPing();
  700.   
  701.   [menuList getNumRows: &r numCols: &c];
  702.   for( i = 0; i < r-1; i++ )
  703.     [[menuList cellAt: i :0] setEnabled: NO];
  704.   [[self mainMenu] display];
  705.   if( !bothsides )
  706.     [setButton setEnabled: NO];
  707.   [gameBoard setEnabled: NO];
  708.   
  709.   bzero( &move_info, sizeof( struct MoveInfo ) );
  710.   move_info.iop = iop;
  711.   move_info.side = side;
  712.   Sdepth = 0;
  713.   SelectMoveStart( &move_info );
  714.  
  715.   while (!timeout && Sdepth < MaxSearchDepth)
  716.     SelectLoop( &move_info );
  717.  
  718.   [self selectMoveEnd];
  719.   
  720.   [self setTitle];
  721.   InCheck();
  722.   NXPing();
  723.   return self;
  724. }
  725.  
  726. - selectMoveEnd
  727. {
  728.   id menuList = [[self mainMenu] itemList];
  729.   int i, r, c;
  730.   
  731.   SelectMoveEnd( &move_info );
  732.   [self updateClocks: computer];
  733.   chess_debug(("computer move time %d, move %s\n",
  734.        GameList[GameCnt].time, mvstr1 ));
  735.   InCheck();
  736.   NXPing();
  737.  
  738.   [menuList getNumRows: &r numCols: &c];
  739.   if( !bothsides )
  740.     for( i = 0; i < r; i++ )
  741.       [[menuList cellAt: i :0] setEnabled: YES];
  742.   [[self mainMenu] display];
  743.   [setButton setEnabled: YES];
  744.   [gameBoard setEnabled: YES];
  745.   NXPing();
  746.  
  747.   [forceButton setEnabled: NO];
  748.   [forceButton display];
  749.   NXPing();
  750.   
  751.  
  752.   return self;
  753. }
  754.  
  755.  
  756.  
  757. - setWhiteName: (char *)wname blackName: (char *)bname
  758. {
  759.   [whiteClockText setStringValue: wname];
  760.   [blackClockText setStringValue: bname];
  761.   if( [whiteSideMatrix selectedRow] == 1 ){
  762.     [whiteName setStringValue: wname];
  763.   }
  764.   else{
  765.     [whiteName setStringValue: COMPUTER];
  766.   }
  767.   if( [blackSideMatrix selectedRow] == 1 ){
  768.     [blackName setStringValue: bname];
  769.   }
  770.   else{
  771.     [blackName setStringValue: COMPUTER];
  772.   }
  773.   return self;
  774. }
  775.  
  776. - (int)whiteTime { return wtime; }
  777. - (int)blackTime { return btime; }
  778. - updateClocks: (int)side
  779. {
  780.   if( !blackClock || !whiteClock )
  781.     return self;
  782.     
  783.   if( side == white ){
  784.     wtime += GameList[GameCnt].time;
  785.     if( [clockWindow isVisible] ){
  786.       [whiteClock setSeconds: wtime];
  787.       [whiteClock display];
  788.     }
  789.   }
  790.   else{
  791.     btime += GameList[GameCnt].time;
  792.     if( [clockWindow isVisible] ){
  793.       [blackClock setSeconds: wtime];
  794.       [blackClock display];
  795.     }
  796.   }
  797.   return self;
  798. }
  799.  
  800. - updateClocks: (int)side seconds: (int) seconds
  801. {
  802.   if( side == white ){
  803.     if( [clockWindow isVisible] ){
  804.       [whiteClock setSeconds: wtime];
  805.       [whiteClock display];
  806.     }
  807.   }
  808.   else{
  809.     if( [clockWindow isVisible] ){
  810.       [blackClock setSeconds: wtime];
  811.       [blackClock display];
  812.     }
  813.   }
  814.   return self;
  815. }
  816.  
  817.  
  818. - setTitle
  819. /*
  820.   Change the board windows title to display the number of cheat commands
  821.   issued.
  822. */
  823. {
  824.   char buf[64];
  825.   if( undoCount || hintCount ){
  826.     sprintf( buf, "Chess:  " );
  827.     if( undoCount ){
  828.       if( undoCount == 1 )
  829.     sprintf( buf+strlen(buf), "1 Undo  " );
  830.       else
  831.     sprintf( buf+strlen(buf), "%d Undos  ", undoCount );
  832.     }
  833.     if( hintCount ){
  834.       if( hintCount == 1 )
  835.     sprintf( buf+strlen(buf), "1 Hint" );
  836.       else
  837.     sprintf( buf+strlen(buf), "%d Hints", hintCount );
  838.     }
  839.   }
  840.   else
  841.     sprintf( buf, "Chess" );
  842.   [boardWindow setTitle: buf];
  843.   return self;
  844. }
  845.  
  846. - setTitleMessage: (char *)m
  847. {
  848.   char *om;
  849.   char buf[128];
  850.   
  851.   [self setTitle];
  852.   om = (char *)[boardWindow title];
  853.   strcpy( buf, om );
  854.   strcat( buf, "   :   " );
  855.   strcat( buf, m );
  856.   [boardWindow setTitle: buf];
  857.   return self;
  858. }
  859.  
  860. @end
  861.